﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XOS_VHD_Tools.VHD;
using System.IO;

namespace XOS_VHD_Tools
{
    public sealed class VHDPartition
    {
        private readonly MBR_ptEntry _entry;
        public VHDPartition(MBR_ptEntry entry, VHDFile disk)
        {
            Disk = disk;
            _entry = entry;

            _driver = new Lazy<IVHDFSDriver>(() =>
                {
                    var drv = VHDFSDriver.GetDriver(this);

                    return drv == null ? new UnknownFS() : drv.Clone() as IVHDFSDriver;
                });
        }

        private class UnknownFS : IVHDFSDriver
        {
            private class RootDir : IDirectory
            {
                private class DescrFile : IFile
                {
                    public DescrFile(RootDir dir)
                    {
                        this.ParentDirectory = dir;
                    }

                    private readonly string _fileContent = @"VHD manager has no driver for this file system, so you can't use it. All the edit operations will fail. 
This file is not a real one - it was generated by VHD manager.";

                    public long Size
                    {
                        get { return Encoding.ASCII.GetByteCount(_fileContent) + 1; }
                    }

                    public System.IO.Stream OpenFile()
                    {
                        return new MemoryStream(Encoding.ASCII.GetBytes(_fileContent), false);
                    }

                    public void Delete()
                    {
                        throw new NotSupportedException("No driver is loaded for this File System");
                    }

                    public void Rename(string newName)
                    {
                        throw new NotSupportedException("No driver is loaded for this File System");
                    }

                    public string Name
                    {
                        get { return "Read me!!!.txt"; }
                    }

                    public IDirectory ParentDirectory
                    {
                        get;
                        private set;
                    }
                }

                public IEnumerable<IDirectory> Directories
                {
                    get { yield break; }
                }

                public IEnumerable<IFile> Files
                {
                    get { yield return new DescrFile(this); }
                }

                public IEnumerable<IFSEntry> Entries
                {
                    get { return Files.Cast<IFSEntry>(); }
                }

                public IDirectory CreateDirectory(string name)
                {
                    throw new NotSupportedException("No driver is loaded for this File System");
                }

                public IFile CreateFile(string name)
                {
                    throw new NotSupportedException("No driver is loaded for this File System");
                }

                public void DeleteItem(IFSEntry entry)
                {
                    throw new NotSupportedException("No driver is loaded for this File System");
                }

                public void RenameItem(IFSEntry entry, string name)
                {
                    throw new NotSupportedException("No driver is loaded for this File System");
                }

                public bool IsRootDirectory
                {
                    get { return true; }
                }

                public string Name
                {
                    get { return "Unknown File System"; }
                }

                public IDirectory ParentDirectory
                {
                    get { return null; }
                }
            }

            public IDirectory RootDirectory
            {
                get { return new RootDir(); }
            }

            public bool Initialize(VHDPartition partition)
            {
                return false;
            }

            public void Format(VHDPartition partition)
            {
            }

            public object Clone()
            {
                return MemberwiseClone();
            }
        }

        public VHDFile Disk { get; private set; }

        /// <summary>
        /// LBA address of first sector of partition
        /// </summary>
        public Int64 FirstSector { get { return _entry.LBA_start; } }
        public Int64 PartSizeSect { get { return _entry.LBA_numOfSect; } }

        public bool IsActive { get { return _entry.active.HasFlag(ActivityFlag.Active); } }

        public PartitionType Type { get { return _entry.type; } }

        private readonly Lazy<IVHDFSDriver> _driver;
        public IVHDFSDriver Driver { get { return _driver.Value; } }

        public byte[] ReadSectors(long sectOffset, int sectToRead)
        {
            sectOffset += FirstSector;

            if (sectOffset < FirstSector || sectOffset >= FirstSector + PartSizeSect)
            {
                throw new ArgumentOutOfRangeException();
            }

            return Disk.ReadSector(sectOffset, sectToRead);
        }

        public void WriteSectors(byte[] bytes, long sectOffset, int sectToWrite)
        {
            sectOffset += FirstSector;

            if (sectOffset < FirstSector || sectOffset >= FirstSector + PartSizeSect)
            {
                throw new ArgumentOutOfRangeException();
            }

            Disk.WriteSector(bytes, sectOffset, sectToWrite);
        }

        public override string ToString()
        {

            return Id + ": " + Type + (_entry.active == ActivityFlag.Active ? "*" : "");
        }

        public int Id { get; set; }


    }
}
